"""Sentry statistics."""
from functools import cached_property
import os

from cki_lib import yaml
from cki_lib.cronjob import CronJob
from cki_lib.logger import get_logger
from cki_lib.session import get_session
import prometheus_client

LOGGER = get_logger(__name__)
SESSION = get_session(__name__)

SENTRY_INSTANCES = yaml.load(contents=os.environ.get('SENTRY_INSTANCES', '[]'))


class SentryAPI:
    """Sentry API handler."""

    def __init__(self, config):
        """Initialize."""
        self.config = config

    def _get(self, endpoint):
        """Do get request to endpoint."""
        headers = {
            'Authorization': 'Bearer ' + os.environ[self.config['token_name']]
        }
        url = self.config['url'] + endpoint.format(**self.config)
        return SESSION.get(url, headers=headers).json()

    @cached_property
    def projects(self):
        """Return the team projects."""
        return self._get('/api/0/teams/{org}/{team}/projects/')

    def get_project_stats(self, project):
        """Return the stats for a project.

        The stats will reset once a day, which the Prometheus counter logic
        should be able to deal with.
        """
        project_slug = project['slug']
        return self._get(f'/api/0/projects/{{org}}/{project_slug}/stats/?resolution=1d')


class SentryMetrics(CronJob):
    """Calculate Sentry metrics."""

    schedule = '*/5 * * * *'

    metric_sentry_events = prometheus_client.Gauge(
        'cki_sentry_events',
        'Number of events in sentry',
        ['instance', 'organization', 'project']
    )

    def __init__(self):
        """Initialize."""
        super().__init__()

        self._apis = {instance['url']: SentryAPI(instance) for instance in SENTRY_INSTANCES}

    def update_project(self, instance, project):
        """Update a single project metrics."""
        project_slug = project['slug']
        organization_slug = instance['org']
        instance_url = instance['url']

        # the stats response is [[timestamp, value], [timestamp, value], ...]
        self.metric_sentry_events.labels(instance_url, organization_slug, project_slug).set(
            self._apis[instance_url].get_project_stats(project)[-1][1])

    def run(self, **_):
        """Update the sentry metrics."""
        for instance in SENTRY_INSTANCES:
            for project in self._apis[instance['url']].projects:
                self.update_project(instance, project)
